using AutoMapper;
using AiPlatformAdmin.Api.Models;
using AiPlatformAdmin.Api.DTOs;

namespace AiPlatformAdmin.Api.Mapping;

public class AutoMapperProfile : Profile
{
    public AutoMapperProfile()
    {
        // Plugin mappings
        CreateMap<Plugin, PluginDto>().ReverseMap();
        CreateMap<CreatePluginDto, Plugin>();
        CreateMap<UpdatePluginDto, Plugin>()
            .ForAllMembers(opt => opt.Condition((src, dest, srcMember) => srcMember != null));

        // LLM Model mappings
        CreateMap<User, SimpleUserDto>();
        CreateMap<LlmModel, LlmModelDto>()
            .ForMember(dest => dest.Category, opt => opt.MapFrom(src => src.Category.ToString()))
            .ForMember(dest => dest.CreatedBy, opt => opt.MapFrom(src => src.CreatedBy));
        CreateMap<CreateLlmModelDto, LlmModel>()
            .ForMember(dest => dest.Category, opt => opt.Ignore());
        CreateMap<UpdateLlmModelDto, LlmModel>()
            .ForAllMembers(opt => opt.Condition((src, dest, srcMember) => srcMember != null));

        // Agent mappings
        CreateMap<Agent, AgentDto>()
            .ForMember(dest => dest.AdminUserIds, opt => opt.MapFrom(src => src.AgentAdmins.Select(aa => aa.UserId)))
            .ForMember(dest => dest.TeamAccessIds, opt => opt.MapFrom(src => src.AgentTeamAccesses.Select(ata => ata.TeamId)))
            .ForMember(dest => dest.KnowledgeBaseIds, opt => opt.MapFrom(src => src.AgentKnowledgeBases.Select(akb => akb.KnowledgeBaseId)))
            .ForMember(dest => dest.PluginIds, opt => opt.MapFrom(src => src.AgentPlugins.Select(ap => ap.PluginId)));
        CreateMap<CreateAgentDto, Agent>()
            .ForMember(dest => dest.AgentAdmins, opt => opt.Ignore())
            .ForMember(dest => dest.AgentTeamAccesses, opt => opt.Ignore())
            .ForMember(dest => dest.AgentKnowledgeBases, opt => opt.Ignore())
            .ForMember(dest => dest.AgentPlugins, opt => opt.Ignore());
        CreateMap<UpdateAgentDto, Agent>()
            .ForAllMembers(opt => opt.Condition((src, dest, srcMember) => srcMember != null));

        // KnowledgeBase mappings
        CreateMap<KnowledgeBase, KnowledgeBaseDto>()
            .ForMember(dest => dest.AdminUserIds, opt => opt.MapFrom(src => src.KnowledgeBaseAdmins.Select(kba => kba.UserId)))
            .ForMember(dest => dest.TeamAccessIds, opt => opt.MapFrom(src => src.KnowledgeBaseTeamAccesses.Select(kbta => kbta.TeamId)))
            .ForMember(dest => dest.DocumentCount, opt => opt.MapFrom(src => src.Documents.Count));
        CreateMap<CreateKnowledgeBaseDto, KnowledgeBase>()
            .ForMember(dest => dest.KnowledgeBaseAdmins, opt => opt.Ignore())
            .ForMember(dest => dest.KnowledgeBaseTeamAccesses, opt => opt.Ignore());
        CreateMap<UpdateKnowledgeBaseDto, KnowledgeBase>()
            .ForAllMembers(opt => opt.Condition((src, dest, srcMember) => srcMember != null));

        // Team mappings
        CreateMap<Team, TeamDto>()
            .ForMember(dest => dest.MemberUserIds, opt => opt.MapFrom(src => src.UserTeams.Select(ut => ut.UserId)))
            .ForMember(dest => dest.AdminUserIds, opt => opt.MapFrom(src => src.TeamAdmins.Select(ta => ta.UserId)));
        CreateMap<CreateTeamDto, Team>()
            .ForMember(dest => dest.UserTeams, opt => opt.Ignore())
            .ForMember(dest => dest.TeamAdmins, opt => opt.Ignore());
        CreateMap<UpdateTeamDto, Team>()
            .ForAllMembers(opt => opt.Condition((src, dest, srcMember) => srcMember != null));

        // User mappings
        CreateMap<User, UserDto>()
            .ForMember(dest => dest.Roles, opt => opt.MapFrom(src => src.Roles.Split(',', StringSplitOptions.RemoveEmptyEntries)))
            .ForMember(dest => dest.TeamIds, opt => opt.MapFrom(src => src.UserTeams.Select(ut => ut.TeamId)));
        CreateMap<CreateUserDto, User>()
            .ForMember(dest => dest.PasswordHash, opt => opt.Ignore())
            .ForMember(dest => dest.Roles, opt => opt.MapFrom(src => string.Join(",", src.Roles)))
            .ForMember(dest => dest.UserTeams, opt => opt.Ignore());
        CreateMap<UpdateUserDto, User>()
            .ForMember(dest => dest.PasswordHash, opt => opt.Ignore())
            .ForMember(dest => dest.Roles, opt => opt.MapFrom((src, dest) => src.Roles != null ? string.Join(",", src.Roles) : dest.Roles))
            .ForAllMembers(opt => opt.Condition((src, dest, srcMember) => srcMember != null));

        // Document mappings
        CreateMap<Document, DocumentDto>();
        CreateMap<CreateDocumentDto, Document>();
        CreateMap<UpdateDocumentDto, Document>()
            .ForAllMembers(opt => opt.Condition((src, dest, srcMember) => srcMember != null));

        // TokenUsage mappings
        CreateMap<TokenUsage, TokenUsageDto>()
            .ForMember(dest => dest.Username, opt => opt.MapFrom(src => src.User.Username))
            .ForMember(dest => dest.AgentName, opt => opt.MapFrom(src => src.Agent.Name));
        CreateMap<CreateTokenUsageDto, TokenUsage>();

        // Tenant mappings
        CreateMap<Tenant, TenantDto>();
        CreateMap<CreateTenantDto, Tenant>();
        CreateMap<UpdateTenantDto, Tenant>()
            .ForAllMembers(opt => opt.Condition((src, dest, srcMember) => srcMember != null));
    }
}
